/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
 */

/* misc2.c  requantization, stereo processing, reordering(shortbl) and antialiasing butterflies
 *
 * misc.c was created by tomislav uzelac in May 1996, and was completely awful
 * Created by: tomislav uzelac Dec 22 1996
 * some more speed injected, cca. Jun 1 1997
 */
#include <math.h>

#include "amp.h"
#include "audio.h"
#include "getdata.h"
#include "huffman.h"

#define MISC2
#include "misc2.h"

/*
 * fras == Formula for Requantization and All Scaling **************************
 */
static inline float fras_l(int sfb,int global_gain,int scalefac_scale,int scalefac,int preflag)
{
    register int a,scale;
    /*
     if (scalefac_scale) scale=2;
     else scale=1;
     */
    scale=scalefac_scale+1;
    a= global_gain -210 -(scalefac << scale);
    if (preflag) a-=(t_pretab[sfb] << scale);

    /* bugfix, Mar 13 97: shifting won't produce a legal result if we shift by more than 31
     * since global_gain<256, this can only occur for (very) negative values of a.
     */
    if (a < -127) return 0;

    /* a minor change here as well, no point in abs() if we now that a<0
     */
    if (a>=0) return tab[a&3]*(1 << (a>>2));
    else return tabi[(-a)&3]/(1 << ((-a) >> 2));
}

static inline float fras_s(int global_gain,int subblock_gain,int scalefac_scale,int scalefac)
{
    int a;
    a=global_gain - 210 - (subblock_gain << 3);
    if (scalefac_scale) a-= (scalefac << 2);
    else a-= (scalefac << 1);

    if (a < -127) return 0;

    if (a>=0) return tab[a&3]*(1 << (a>>2));
    else return tabi[(-a)&3]/(1 << ((-a) >> 2));
}

/* this should be faster than Power()
 */
static inline float fras2(int is,float a)
{
    if (is > 0) return t_43[is]*a;
    else return -t_43[-is]*a;
}

/*
 * requantize_mono *************************************************************
 */

/* generally, the two channels do not have to be of the same block type - that's why we do two passes with requantize_mono.
 * if ms or intensity stereo is enabled we do a single pass with requantize_ms because both channels are same block type
 */

void requantize_mono(int gr,int ch,struct SIDE_INFO *info,struct AUDIO_HEADER *header)
{
    int l,i,sfb;
    float a;
    int global_gain=info->global_gain[gr][ch];
    int scalefac_scale=info->scalefac_scale[gr][ch];
    int sfreq=header->sampling_frequency;


    no_of_imdcts[0]=no_of_imdcts[1]=32;

    if (info->window_switching_flag[gr][ch] && info->block_type[gr][ch]==2)
        if (info->mixed_block_flag[gr][ch]) {
            /*
             * requantize_mono - mixed blocks/long block part **********************
             */
            int window,window_len,preflag=0; /* pretab is all zero in this low frequency area */
            int scalefac=scalefac_l[gr][ch][0];

            l=0;sfb=0;
            a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
            while (l<36) {
                xr[ch][0][l]=fras2(is[ch][l],a);
                if (l==t_l[sfb]) {
                    scalefac=scalefac_l[gr][ch][++sfb];
                    a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
                }
                l++;
            }
            /*
             * requantize_mono - mixed blocks/short block part *********************
             */
            sfb=3;
            window_len=t_s[sfb]-t_s[sfb-1];
            while (l<non_zero[ch]) {
                for (window=0;window<3;window++) {
                    int scalefac=scalefac_s[gr][ch][sfb][window];
                    int subblock_gain=info->subblock_gain[gr][ch][window];
                    a=fras_s(global_gain,subblock_gain,scalefac_scale,scalefac);
                    for (i=0;i<window_len;i++) {
                        xr[ch][0][t_reorder[header->ID][sfreq][l]]=fras2(is[ch][l],a);
                        l++;
                    }
                }
                sfb++;
                window_len=t_s[sfb]-t_s[sfb-1];
            }
            while (l<576) xr[ch][0][t_reorder[header->ID][sfreq][l++]]=0;
        } else {
            /*
             * requantize mono - short blocks **************************************
             */
            int window,window_len;

            sfb=0; l=0;
            window_len=t_s[0]+1;
            while (l<non_zero[ch]) {
                for (window=0;window<3;window++) {
                    int scalefac=scalefac_s[gr][ch][sfb][window];
                    int subblock_gain=info->subblock_gain[gr][ch][window];
                    float a=fras_s(global_gain,subblock_gain,scalefac_scale,scalefac);
                    for (i=0;i<window_len;i++) {
                        xr[ch][0][t_reorder[header->ID][sfreq][l]]=fras2(is[ch][l],a);
                        l++;
                    }
                }
                sfb++;
                window_len=t_s[sfb]-t_s[sfb-1];
            }
            while (l<576) xr[ch][0][t_reorder[header->ID][sfreq][l++]]=0;
        }
    else {
        /* long blocks */
        int preflag=info->preflag[gr][ch];
        int scalefac=scalefac_l[gr][ch][0];

        sfb=0; l=0;
        a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
        while (l<non_zero[ch]) {
            xr[ch][0][l]=fras2(is[ch][l],a);
            if (l==t_l[sfb]) {
                scalefac=scalefac_l[gr][ch][++sfb];
                a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
            }
            l++;
        }
        while (l<576) xr[ch][0][l++]=0;
    }
}

/*
 * stereo stuff ****************************************************************
 */
static int find_isbound(int isbound[3],int gr,struct SIDE_INFO *info,struct AUDIO_HEADER *header)
{
    int sfb,window,window_len,ms_flag,tmp,i;

    isbound[0]=isbound[1]=isbound[2]=-1;
    no_of_imdcts[0]=no_of_imdcts[1]=32;

    if (header->mode_extension==1 || header->mode_extension==3) {
        if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2) {

            /* find that isbound!
             */
            tmp=non_zero[1];
            sfb=0; while ((3*t_s[sfb]+2) < tmp  && sfb < 12) sfb++;
            while ((isbound[0]<0 || isbound[1]<0 || isbound[2]<0) && !(info->mixed_block_flag[gr][0] && sfb<3) && sfb) {
                for (window=0;window<3;window++) {
                    if (sfb==0) {
                        window_len=t_s[0]+1;
                        tmp=(window+1)*window_len - 1;
                    } else {
                        window_len=t_s[sfb]-t_s[sfb-1];
                        tmp=(3*t_s[sfb-1]+2) + (window+1)*window_len;
                    }
                    if (isbound[window] < 0)
                        for (i=0;i<window_len;i++)
                            if (is[1][tmp--] != 0) {
                                isbound[window]=t_s[sfb]+1;
                                break;
                            }
                }
                sfb--;
            }

            /* mixed block magic now...
             */
            if (sfb==2 && info->mixed_block_flag[gr][0])
            {
                if (isbound[0]<0 && isbound[1]<0 && isbound[2]<0) {
                    tmp=35;
                    while (is[1][tmp] == 0) tmp--;
                    sfb=0; while (t_l[sfb] < tmp  && sfb < 21) sfb++;
                    isbound[0]=isbound[1]=isbound[2]=t_l[sfb]+1;
                } else for (window=0;window<3;window++)
                    if (isbound[window]<0) isbound[window]=36;
            }
            if (header->ID==1) isbound[0]=isbound[1]=isbound[2]=MAX(isbound[0],MAX(isbound[1],isbound[2]));

            /* just how many imdcts?
             */
            tmp=non_zero[0];
            sfb=0; while ((3*t_s[sfb]+2) < tmp && sfb < 12) sfb++;
            no_of_imdcts[0]=no_of_imdcts[1]=(t_s[sfb]-1)/6+1;
        } else {

            /* long blocks now
             */
            tmp=non_zero[1];
            while (is[1][tmp] == 0) tmp--;
            sfb=0; while (t_l[sfb] < tmp && sfb < 21) sfb++;
            isbound[0]=isbound[1]=isbound[2]=t_l[sfb]+1;
            no_of_imdcts[0]=no_of_imdcts[1]=(non_zero[0]-1)/18+1;
        }
        if (header->mode_extension==1) ms_flag=0;
        else ms_flag=1;
    } else {

        /* intensity stereo is, regretably, turned off
         */
        ms_flag=1;

        /* i really put a lot of work in this, but it still looks like shit (works, though)
         */
        if (!info->window_switching_flag[gr][0] || (info->window_switching_flag[gr][0] && info->block_type[gr][0]!=2))
            isbound[0]=isbound[1]=isbound[2]=(MAX(non_zero[0],non_zero[1]));
        else isbound[0]=isbound[1]=isbound[2]=576;

        if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2) {
            /* should do for mixed blocks too, though i havent tested... */
            tmp=(MAX(non_zero[0],non_zero[1]))/3;
            sfb=0; while (t_s[sfb]<tmp && sfb<12) sfb++;
            no_of_imdcts[0]=no_of_imdcts[1]=(t_s[sfb]-1)/6+1;
        }
        else no_of_imdcts[0]=no_of_imdcts[1]=(isbound[0]-1)/18+1;

    }

    return ms_flag;
}

static inline void stereo_s(int l,float a[2],int pos,int ms_flag,int is_pos,struct AUDIO_HEADER *header)
{
    float ftmp,Mi,Si;

    if (l>=576) return; /* brrr... */

    if ((is_pos != IS_ILLEGAL) && (header->ID==1)) {
        ftmp=fras2(is[0][l],a[0]);
        xr[0][0][pos]=(1-t_is[is_pos])*ftmp;
        xr[1][0][pos]=t_is[is_pos]*ftmp;
        return;
    }

    if ((is_pos != IS_ILLEGAL) && (header->ID==0)) {
        ftmp=fras2(is[0][l],a[0]);
        if (is_pos&1) {
            xr[0][0][pos]= t_is2[intensity_scale][(is_pos+1)>>1] * ftmp;
            xr[1][0][pos]= ftmp;
        } else {
            xr[0][0][pos]= ftmp;
            xr[1][0][pos]= t_is2[intensity_scale][is_pos>>1] * ftmp;
        }
        return;
    }

    if (ms_flag) {
        Mi=fras2(is[0][l],a[0]);
        Si=fras2(is[1][l],a[1]);
        xr[0][0][pos]=(Mi+Si)*i_sq2;
        xr[1][0][pos]=(Mi-Si)*i_sq2;
    } else {
        xr[0][0][pos]=fras2(is[0][l],a[0]);
        xr[1][0][pos]=fras2(is[1][l],a[1]);
    }
}

static inline void stereo_l(int l,float a[2],int ms_flag,int is_pos,struct AUDIO_HEADER *header)
{
    float ftmp,Mi,Si;
    if (l>=576) return;

    /* new code by ???
     */
    if (is_pos != IS_ILLEGAL) {
        ftmp = fras2(is[0][l], a[0]);
        if (header -> ID ==1) {
            xr[0][0][l] = (1 - t_is[is_pos]) * ftmp;
            xr[1][0][l] = t_is[is_pos] * ftmp;
            return;
        } else if (is_pos & 1) {
            xr[0][0][l] = t_is2[intensity_scale][(is_pos + 1) >> 1] * ftmp;
            xr[1][0][l] = ftmp;
        } else {
            xr[0][0][l] = ftmp;
            xr[1][0][l] = t_is2[intensity_scale][is_pos >> 1] * ftmp;
        }
        return;
    }

    if (ms_flag) {
        Mi=fras2(is[0][l],a[0]);
        Si=fras2(is[1][l],a[1]);
        xr[0][0][l]=(Mi+Si)*i_sq2;
        xr[1][0][l]=(Mi-Si)*i_sq2;
    } else {
        xr[0][0][l]=fras2(is[0][l],a[0]);
        xr[1][0][l]=fras2(is[1][l],a[1]);
    }

}


/*
 * requantize_ms ***************************************************************
 */
void requantize_ms(int gr,struct SIDE_INFO *info,struct AUDIO_HEADER *header)
{
    int l,sfb,ms_flag,is_pos,i,ch;
    int *global_gain,subblock_gain[2],*scalefac_scale,scalefac[2],isbound[3];
    int sfreq=header->sampling_frequency;
    int id = header->ID;
    float a[2];

    global_gain=info->global_gain[gr];
    scalefac_scale=info->scalefac_scale[gr];

    if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2)
        if (info->mixed_block_flag[gr][0]) {
            /*
             * mixed blocks w/stereo processing - long block part ******************
             */
            int window,window_len;
            int preflag[2]={0,0};

            ms_flag=find_isbound(isbound,gr,info,header);

            sfb=0; l=0;
            for (ch=0;ch<2;ch++) {
                scalefac[ch]=scalefac_l[gr][ch][0];
                a[ch]=fras_l(0,global_gain[ch],scalefac_scale[ch],scalefac[ch],preflag[ch]);
            }


            while (l<36) {
                int is_pos;
                if (l<isbound[0]) is_pos=IS_ILLEGAL;
                else {
                    is_pos=scalefac[1];
                    if (id==1) /* MPEG1 */
                    {
                        if (is_pos==7) is_pos=IS_ILLEGAL;
                        else /* MPEG2 */
                            if (is_pos==is_max[sfb]) is_pos=IS_ILLEGAL;
                    }
                }

                stereo_l(l,a,ms_flag,is_pos,header);

                if (l==t_l[sfb]) {
                    sfb++;
                    for (ch=0;ch<2;ch++) {
                        scalefac[ch]=scalefac_l[gr][ch][sfb];
                        a[ch]=fras_l(sfb,global_gain[ch],scalefac_scale[ch],scalefac[ch],preflag[ch]);
                    }
                }

                l++;
            }
            /*
             * mixed blocks w/stereo processing - short block part *****************
             */
            sfb=3;
            window_len=t_s[sfb]-t_s[sfb-1];

            while (l<(MAX(non_zero[0],non_zero[1]))) {
                for (window=0;window<3;window++) {
                    subblock_gain[0]=info->subblock_gain[gr][0][window];
                    subblock_gain[1]=info->subblock_gain[gr][1][window];
                    scalefac[0]=scalefac_s[gr][0][sfb][window];
                    scalefac[1]=scalefac_s[gr][1][sfb][window];

                    if (t_s[sfb] < isbound[window]) {
                        is_pos=IS_ILLEGAL;
                        a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
                        a[1]=fras_s(global_gain[1],subblock_gain[1],scalefac_scale[1],scalefac[1]);
                    } else {
                        is_pos=scalefac[1];
                        if (id==1) /* MPEG1 */
                        {
                            if (is_pos==7) is_pos=IS_ILLEGAL;
                            else /* MPEG2 */
                                if (is_pos==is_max[sfb+6]) is_pos=IS_ILLEGAL;
                        }
                        a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
                    }

                    for (i=0;i<window_len;i++) {
                        stereo_s(l,a,t_reorder[id][sfreq][l],ms_flag,is_pos,header);
                        l++;
                    }
                }
                sfb++;
                window_len=t_s[sfb]-t_s[sfb-1];
            }
            while (l<576) {
                int reorder = t_reorder[id][sfreq][l++];

                xr[0][0][reorder]=xr[1][0][reorder]=0;
            }
        } else {
            /*
             * requantize_ms - short blocks w/stereo processing ********************
             */
            int window,window_len;

            ms_flag=find_isbound(isbound,gr,info,header);
            sfb=0; l=0;
            window_len=t_s[0]+1;

            while (l<(MAX(non_zero[0],non_zero[1]))) {
                for (window=0;window<3;window++) {
                    subblock_gain[0]=info->subblock_gain[gr][0][window];
                    subblock_gain[1]=info->subblock_gain[gr][1][window];
                    scalefac[0]=scalefac_s[gr][0][sfb][window];
                    scalefac[1]=scalefac_s[gr][1][sfb][window];

                    if (t_s[sfb] < isbound[window]) {
                        is_pos=IS_ILLEGAL;
                        a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
                        a[1]=fras_s(global_gain[1],subblock_gain[1],scalefac_scale[1],scalefac[1]);
                    } else {
                        is_pos=scalefac[1];
                        if (id==1) /* MPEG1 */
                        {
                            if (is_pos==7) is_pos=IS_ILLEGAL;
                            else /* MPEG2 */
                                if (is_pos==is_max[sfb+6]) is_pos=IS_ILLEGAL;
                        }
                        a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
                    }

                    for (i=0;i<window_len;i++) {
                        stereo_s(l,a,t_reorder[id][sfreq][l],ms_flag,is_pos,header);
                        l++;
                    }
                }
                /* this won't do anymore
                 * window_len=-t_s[sfb]+t_s[++sfb];
                 */
                window_len  = -t_s[sfb++];
                window_len +=  t_s[sfb];

            }
            while (l<576) {
                int reorder = t_reorder[id][sfreq][l++];

                xr[0][0][reorder]=xr[1][0][reorder]=0;
            }
        }
    else {
        /*
         * long blocks w/stereo processing *************************************
         */
        int *preflag=info->preflag[gr];

        ms_flag=find_isbound(isbound,gr,info,header);

        sfb=0; l=0;
        scalefac[0]=scalefac_l[gr][0][sfb];
        a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
        scalefac[1]=scalefac_l[gr][1][sfb];
        a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);

        /* no intensity stereo part
         */
        if (ms_flag)
            while (l< isbound[0]) {
#if defined(PENTIUM_RDTSC)

                unsigned int cnt4, cnt3, cnt2, cnt1;
                static int min_cycles = 99999999;

                __asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt4));
#endif

                {
                    register float Mi = fras2(is[0][l],a[0]);
                    register float Si = fras2(is[1][l],a[1]);
                    register float tmp = i_sq2;
                    xr[0][0][l]=(Mi+Si)*tmp;
                    xr[1][0][l]=(Mi-Si)*tmp;
                }

#if defined(PENTIUM_RDTSC)
                __asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt4));

                if (cnt2-cnt1 < min_cycles) {
                    min_cycles = cnt2-cnt1;
                    printf("%d cycles\n", min_cycles);
                }

#endif
                if (l==t_l[sfb]) {
#if defined(PENTIUM_RDTSC2)

                    unsigned int cnt4, cnt2, cnt1;
                    static int min_cycles = 99999999;

                    __asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt4));
#endif

                    sfb++;
                    scalefac[0]=scalefac_l[gr][0][sfb];
                    a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
                    scalefac[1]=scalefac_l[gr][1][sfb];
                    a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);
#if defined(PENTIUM_RDTSC2)
                    __asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt4));

                    if (cnt2-cnt1 < min_cycles) {
                        min_cycles = cnt2-cnt1;
                        printf("%d cycles, sfb %d\n", min_cycles, sfb);
                    }

#endif
                }
                l++;
            }
        else
            while (l< isbound[0]) {
                xr[0][0][l]=fras2(is[0][l],a[0]);
                xr[1][0][l]=fras2(is[1][l],a[1]);
                if (l==t_l[sfb]) {
                    sfb++;
                    scalefac[0]=scalefac_l[gr][0][sfb];
                    a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
                    scalefac[1]=scalefac_l[gr][1][sfb];
                    a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);
                }
                l++;
            }


        /* intensity stereo part
         */
        while (l<(MAX(non_zero[0],non_zero[1]))) {
            int is_pos=scalefac[1];

            if (id==1) /* MPEG1 */
            {
                if (is_pos==7) is_pos=IS_ILLEGAL;
                else /* MPEG2 */
                    if (is_pos==is_max[sfb]) is_pos=IS_ILLEGAL;
            }
            stereo_l(l,a,ms_flag,is_pos,header);

            if (l==t_l[sfb]) {
                sfb++;
                scalefac[0]=scalefac_l[gr][0][sfb];
                scalefac[1]=scalefac_l[gr][1][sfb];
                a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
            }
            l++;
        }

        while (l<576) {
            xr[0][0][l]=0;
            xr[1][0][l]=0;
            l++;
        }
    }
}

/*
 * requantize_downmix **********************************************************
 */
void requantize_downmix(int gr,struct SIDE_INFO *info,struct AUDIO_HEADER *header)
{
    int l,sfb,ms_flag,is_pos,i,ch;
    int *global_gain,subblock_gain[2],*scalefac_scale,scalefac[2],isbound[3];
    int sfreq=header->sampling_frequency;
    int id = header->ID;
    float a[2];

    /* first set some variables
     */
    global_gain=info->global_gain[gr];
    scalefac_scale=info->scalefac_scale[gr];

    if (header->mode_extension==2 || header->mode_extension==3) ms_flag=1;
    else ms_flag=0;

    /* ... and then we're off for requantization
     */
    if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2)
        if (info->mixed_block_flag[gr][0]) {
            die("mixed block? hmmmm...., downmix for mixed blocks is not yet implemented\n");
        } else {
            int window,window_len;
            int isbound[3];
            int is_pos;
            int dummy=find_isbound(isbound,gr,info,header); /* ugly hack, part3 */

            sfb=0; l=0; window_len=t_s[0]+1;

            while (l<(MAX(non_zero[0],non_zero[1]))) {
                for (window=0;window<3;window++) {
                    subblock_gain[0]=info->subblock_gain[gr][0][window];
                    subblock_gain[1]=info->subblock_gain[gr][1][window];
                    scalefac[0]=scalefac_s[gr][0][sfb][window];
                    is_pos=scalefac[1]=scalefac_s[gr][1][sfb][window];

                    if (t_s[sfb] < isbound[window]) {
                        a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
                        if (ms_flag) {
                            for (i=0;i<window_len;i++) {
                                register float Mi=fras2(is[0][l],a[0]);
                                register float tmp = i_sq2;
                                xr[0][0][t_reorder[id][sfreq][l]]=Mi*i_sq2;
                                l++;
                            }
                        } else {
                            a[1]=fras_s(global_gain[1],subblock_gain[1],scalefac_scale[1],scalefac[1]);
                            for (i=0;i<window_len;i++) {
                                register float tmp1=fras2(is[0][l],a[0]);
                                register float tmp2=fras2(is[1][l],a[1]);
                                xr[0][0][t_reorder[id][sfreq][l]]=(tmp1+tmp2)*0.5f;
                                l++;
                            }
                        }
                    } else {
                        a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
                        for (i=0;i<window_len;i++) {
                            register float ftmp = fras2(is[0][l], a[0]);
                            if (id==0 && is_pos<is_max[sfb])
                                ftmp*=t_downmix[intensity_scale][(is_pos+1)>>1];
                            xr[0][0][t_reorder[id][sfreq][l]] = ftmp;
                            l++;
                        }
                    }
                }
                window_len  = -t_s[sfb++];
                window_len +=  t_s[sfb];
            }
            while (l<576) {
                xr[0][0][l]=0;
                l++;
            }
        }
    else {
        int *preflag=info->preflag[gr];
        int isbound;

        if (header->mode_extension==1 || header->mode_extension==3) {
            int tmp=non_zero[1];
            while (is[1][tmp] == 0) tmp--;
            sfb=0; while (t_l[sfb] < tmp && sfb < 21) sfb++;
            isbound=t_l[sfb]+1;
            no_of_imdcts[0]=no_of_imdcts[1]=(non_zero[0]-1)/18+1;
        } else {
            isbound=(MAX(non_zero[0],non_zero[1]));
            no_of_imdcts[0]=no_of_imdcts[1]=(isbound-1)/18+1;
        }

        sfb=0; l=0;
        scalefac[0]=scalefac_l[gr][0][sfb];
        a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
        scalefac[1]=scalefac_l[gr][1][sfb];
        a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);

        /* no intensity stereo part
         */
        if (ms_flag)
            while (l < isbound) {
                register float Mi = fras2(is[0][l],a[0]);
                register float tmp = i_sq2;
                xr[0][0][l]=Mi*tmp;

                if (l==t_l[sfb]) {
                    sfb++;
                    scalefac[0]=scalefac_l[gr][0][sfb];
                    a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
                    scalefac[1]=scalefac_l[gr][1][sfb];
                }
                l++;
            }
        else
            while (l < isbound) {
                register float tmp1=fras2(is[0][l],a[0]);
                register float tmp2=fras2(is[1][l],a[1]);
                xr[0][0][l]=(tmp1+tmp2)*0.5f;
                if (l==t_l[sfb]) {
                    sfb++;
                    scalefac[0]=scalefac_l[gr][0][sfb];
                    a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
                    scalefac[1]=scalefac_l[gr][1][sfb];
                    a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);
                }
                l++;
            }
        /* intensity stereo part
         */
        while (l<(MAX(non_zero[0],non_zero[1]))) {
            int is_pos=scalefac[1];
            register float ftmp=fras2(is[0][l], a[0]);

            if (id==0  && is_pos<is_max[sfb]) {
                ftmp*=t_downmix[intensity_scale][(is_pos+1)>>1];
            }

            xr[0][0][l] = ftmp;

            if (l==t_l[sfb]) {
                sfb++;
                scalefac[0]=scalefac_l[gr][0][sfb];
                a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
                scalefac[1]=scalefac_l[gr][1][sfb];
            }
            l++;
        }

        /* _always_ zero out everything else
         */
        while (l<576) {
            xr[0][0][l]=0;
            l++;
        }
    }
}

/*
 * antialiasing butterflies ****************************************************
 *
 */
void alias_reduction(int ch)
{
    unsigned int sb;

    for (sb=1;sb<32;sb++) {
        float *x = xr[ch][sb];
        register float a, b;

        a = x[0];
        b = x[-1];
        x[-1] = b * Cs[0] - a * Ca[0];
        x[0]  = a * Cs[0] + b * Ca[0];

        a = x[1];
        b = x[-2];
        x[-2] = b * Cs[1] - a * Ca[1];
        x[1]  = a * Cs[1] + b * Ca[1];

        a = x[2];
        b = x[-3];
        x[-3] = b * Cs[2] - a * Ca[2];
        x[2]  = a * Cs[2] + b * Ca[2];

        a = x[3];
        b = x[-4];
        x[-4] = b * Cs[3] - a * Ca[3];
        x[3]  = a * Cs[3] + b * Ca[3];

        a = x[4];
        b = x[-5];
        x[-5] = b * Cs[4] - a * Ca[4];
        x[4]  = a * Cs[4] + b * Ca[4];

        a = x[5];
        b = x[-6];
        x[-6] = b * Cs[5] - a * Ca[5];
        x[5]  = a * Cs[5] + b * Ca[5];

        a = x[6];
        b = x[-7];
        x[-7] = b * Cs[6] - a * Ca[6];
        x[6]  = a * Cs[6] + b * Ca[6];

        a = x[7];
        b = x[-8];
        x[-8] = b * Cs[7] - a * Ca[7];
        x[7]  = a * Cs[7] + b * Ca[7];
    }
}

/* calculating t_43 instead of having that big table in misc2.h
 */

void calculate_t43(void)
{
    int i;
    for (i=0;i<8192;i++)
        t_43[i]=(float)Power((float)i,1.33333333333f);
}
